﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace NDF.ConnectionLibrary
{
	public struct UserDetails
	{
		#region Fields

		private string mUserName;
		private string mPassword;
		private int mUserID;

		private static int LastRegisteredUserID;

		private static int MinPasswordLength = 6;
		private static int MaxPasswordLength = 18;
		private static int MinUserNameLength = 6;
		private static int MaxUserNameLength = 18;

		private static HashAlgorithm Algorithm;

		#endregion

		public UserDetails(string userName, string password)
		{
			if (userName == password)
				throw new ArgumentException("Username and password cannot be the same!");

			if (string.IsNullOrEmpty(userName))
				throw new ArgumentException("Username must not be null or empty");
			if (string.IsNullOrEmpty(password))
				throw new ArgumentException("Password must not be null or empty");

			if (ValidateUserName(userName))
			{
				mUserName = userName;
			}
			else
			{
				throw new ArgumentException("Invalid or taken username", "userName");
			}
			if (ValidatePassword(password))
			{
				mPassword = Encrypt(password);
			}
			else
			{
				throw new ArgumentException("Invalid password", "password");
			}

			LastRegisteredUserID++;
			mUserID = LastRegisteredUserID;
		}

		/// <summary>
		/// Gets or sets the player`s username.
		/// </summary>
		public string Username
		{
			get { return mUserName; }
			set 
			{
				if (ValidateUserName(value))
					mUserName = value;
				else
					throw new ArgumentException("Invalid or taken username","userName");					
			}
		}

		/// <summary>
		/// Gets the player`s ID.
		/// </summary>
		public int UserID
		{
			get { return mUserID; }
		}

		/// <summary>
		/// Validates the given username.
		/// </summary>
		private static bool ValidateUserName(string userName)
		{
			if (userName.Length < MinUserNameLength || userName.Length > MaxUserNameLength)
				return false;
			return true;
		}

		/// <summary>
		/// Validates the given password.
		/// </summary>
		private static bool ValidatePassword(string password)
		{
			if (password.Length < MinPasswordLength || password.Length > MaxPasswordLength)
				return false;

			return true;
		}

		/// <summary>
		/// Encrypts the given password.
		/// </summary>
		private static string Encrypt(string password)
		{
			if (Algorithm == null)
				Algorithm = new SHA512Managed();

			byte[] passwordInBytes = Encoding.UTF8.GetBytes(password);
			byte[] encryptedInBytes = Algorithm.ComputeHash(passwordInBytes);
			string hashCode = Encoding.UTF8.GetString(encryptedInBytes);
			return hashCode;
		}

		/// <summary>
		/// Checks whether the given password matches the known password.
		/// </summary>
		/// <param name="password">The password to test.</param>
		/// <returns>True if the passwords match, false otherwise</returns>
		/// <exception cref="System.ArgumentNullException"/>
		public bool CheckPassword(string password)
		{
			if (string.IsNullOrEmpty(password))
				throw new ArgumentException("Password cannot be null or empty", "password");

			return this.mPassword == Encrypt(password);
		}

	}
}
